﻿/*
Copyright © 2012 Microsoft. All rights reserved.

This code released under the terms of the Microsoft Public License (MS-PL)

This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.

1. Definitions
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
same meaning here as under U.S. copyright law.
A "contribution" is the original software, or any additions or changes to the software.
A "contributor" is any person that distributes its contribution under this license.
"Licensed patents" are a contributor's patent claims that read directly on its contribution.

2. Grant of Rights
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.

3. Conditions and Limitations
(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WindowsFormsApplication1.SPFAdmin;
using WindowsFormsApplication1.SPFVMM;
using System.Data.Services.Client;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        #region SPF helpers
        private UserRole loggedInUserRole = null;
        private bool IsValidUserRole()
        {
            var userRoles = VmmContextInstance("Administrator").UserRoles.Where(q => q.Name == user.Text).ToArray();
            if(userRoles.Count() == 1 )
            {
                loggedInUserRole = userRoles.First();
                return true;
            }
            loggedInUserRole = null;
            return false;
        }

        private void CreateUserRole(string name)
        {
            var membersToAdd = new System.Collections.ObjectModel.ObservableCollection<string>();
            membersToAdd.Add(user.Text);

            var t = new Tenant
                {
                    Name = name
                };
            AdminContextInstance().AddToTenants(t);
            AdminContextInstance().SaveChanges();
            
            var myStamp = AdminContextInstance().Stamps.First();
            AdminContextInstance().AddLink(t, "Stamps", myStamp);
            AdminContextInstance().SaveChanges();

            var cloud = VmmContextInstance().Clouds.First();
            var ur = VmmContextInstance().UserRoles.Where(q => q.ID == t.ID).First();
            ur.AddScope = new System.Collections.ObjectModel.ObservableCollection<UserRoleScope>{
                new UserRoleScope 
                { 
                    Scope = cloud.ID, 
                    StampId = cloud.StampId,
                    ScopeType = "Cloud"
                }};
            VmmContextInstance().UpdateObject(ur);
            VmmContextInstance().SaveChanges();

            var templates = VmmContextInstance().VMTemplates;
            foreach (var template in templates)
            {
                ur.AddResource = new System.Collections.ObjectModel.ObservableCollection<UserRoleResource>{
                    new UserRoleResource 
                    { 
                        Resource = template.ID,
                        StampId = cloud.StampId,
                        ResourceType = "VMTemplate"
                    }};
                VmmContextInstance().UpdateObject(ur);
                VmmContextInstance().SaveChanges();
            }

            ur.PermissionInput = new System.Collections.ObjectModel.ObservableCollection<UserRolePermission>{
                new UserRolePermission
                { 
                    Permission = new System.Collections.ObjectModel.ObservableCollection<string>
                        {
                            "Create", 
                            "PauseAndResume",
                            "Start",
                            "Stop",
                            "AllowLocalAdmin",
                            "RemoteConnect",
                            "Remove",
                            "Shutdown",
                            "Checkpoint",
                            "Store",
                            "Save",
                            "Author",
                            "CreateFromVHDOrTemplate",
                            "CheckpointRestoreOnly",
                            "AuthorVMNetwork"
                        },
                        StampId = cloud.StampId
                }
            };
            VmmContextInstance().UpdateObject(ur);
            VmmContextInstance().SaveChanges();
        }
                  

        private IEnumerable<Cloud> GetClouds()
        {
            return VmmContextInstance().Clouds;
        }

        private void CreateVm(string name, string vhdName)
        {
            var cloud = VmmContextInstance().Clouds.First();
            var template = VmmContextInstance().VMTemplates.Where(q => q.Name == vhdName && q.StampId == cloud.StampId).First();
            var vm = new VirtualMachine
                {
                    Name = name,
                    CloudId = cloud.ID,
                    StampId = cloud.StampId,
                    VMTemplateId = template.ID,
                };
            VmmContextInstance().AddToVirtualMachines(vm);
            VmmContextInstance().SaveChanges();
        }

        private void StopVm(Guid g)
        {
            var vm = VmmContextInstance().VirtualMachines.Where(q => q.ID == g).First();
            vm.Operation = "Stop";
            VmmContextInstance().UpdateObject(vm);
            VmmContextInstance().SaveChanges();
        }

        private void StartVm(Guid g)
        {
            var vm = VmmContextInstance().VirtualMachines.Where(q => q.ID == g).First();
            vm.Operation = "Start";
            VmmContextInstance().UpdateObject(vm);
            VmmContextInstance().SaveChanges();
        }

        private void DeleteVm(Guid g)
        {
            var vm = VmmContextInstance().VirtualMachines.Where(q => q.ID == g).First();
            VmmContextInstance().DeleteObject(vm);
            VmmContextInstance().SaveChanges();
        }

        private IEnumerable<VirtualMachine> GetVMs()
        {
            return VmmContextInstance().VirtualMachines;
        }

        private IEnumerable<UserRole> GetUserRoles()
        {
            return VmmContextInstance().UserRoles;
        }

        private void DeleteUserRole(Guid guid)
        {
            var ur = VmmContextInstance().UserRoles.Where(q => q.ID == guid).First();
            var g = ur.ID;

            var t = AdminContextInstance().Tenants.Where(q => q.ID == g).First();
            AdminContextInstance().DeleteObject(t);
            AdminContextInstance().SaveChanges();
            AdminContextInstance().Detach(t);
        }

        private static object sync = new object();

        private static Dictionary<string, VMM> VmmContextCache { get; set; }

        private static void OnSendingRequest(object sender, SendingRequestEventArgs e)
        {
            // Add an Authorization header that contains an OAuth WRAP access token to the request.
            e.RequestHeaders.Add("x-ms-principal-id", "[test]");
        }

        private VMM VmmContextInstance()
        {
            return VmmContextInstance(user.Text);
        }

        private VMM VmmContextInstance(string s)
        {
            if (VmmContextCache == null || !VmmContextCache.ContainsKey(user.Text))
            {
                lock (sync)
                {
                    if (VmmContextCache == null)
                    {
                        VmmContextCache = new Dictionary<string, VMM>();
                    }

                    if (!VmmContextCache.ContainsKey(s))
                    {
                        VMM context = null;
                        if(s != "Administrator")
                        {
                            // Create subscription auth mode context
                            context = new VMM(new Uri(string.Format("https://{1}:8090/SC2012/VMM/{0}/Microsoft.Management.Odata.svc", loggedInUserRole.ID.ToString().Replace("{","").Replace("}",""), textBox1.Text)));
                            context.SendingRequest += new EventHandler<SendingRequestEventArgs>(OnSendingRequest);
                        }
                        else
                        {
                            // Create admin auth mode context
                            context = new VMM(new Uri(string.Format("https://{0}:8090/SC2012/VMM/Microsoft.Management.Odata.svc", textBox1.Text)));
                        }
                        
                        // account used must be member of administrators VMM role
                        context.Credentials = System.Net.CredentialCache.DefaultCredentials;

                        // use OverwriteChanges to see updates made by VMM
                        context.MergeOption = System.Data.Services.Client.MergeOption.OverwriteChanges;
                        VmmContextCache.Add(s, context);
                        return context;
                    }
                }
            }
            return VmmContextCache[s];
        }

        private static Dictionary<string, Admin> AdminContextCache { get; set; }

        private Admin AdminContextInstance()
        {
            if (AdminContextCache == null || !AdminContextCache.ContainsKey(user.Text))
            {
                lock (sync)
                {
                    if (AdminContextCache == null)
                    {
                        AdminContextCache = new Dictionary<string, Admin>();
                    }

                    if (!AdminContextCache.ContainsKey(user.Text))
                    {
                        var context = new Admin(new Uri(string.Format("https://{0}:8090/SC2012/Admin/Microsoft.Management.Odata.svc", textBox1.Text)));
                        context.Credentials = System.Net.CredentialCache.DefaultCredentials;
                        context.MergeOption = System.Data.Services.Client.MergeOption.OverwriteChanges;
                        AdminContextCache.Add(user.Text, context);
                        return context;
                    }
                }
            }
            return AdminContextCache[user.Text];
        }
        #endregion

        #region UI event handlers
        private TabPage cachedTab = null;

        private void TenantLoggedIn()
        {
            if (addUserTab.TabPages.Count == 3)
            {
                cachedTab = addUserTab.TabPages[0];
                addUserTab.TabPages.RemoveAt(0);
            }
            addUserTab.Visible = true;
        }

        private void AdminLoggedIn()
        {
            if (addUserTab.TabPages.Count == 2)
            {
                addUserTab.TabPages.Insert(0, cachedTab);
            }
            addUserTab.Visible = true;
        }

        private void signIn_Click(object sender, EventArgs e)
        {
            // TODO: authenticate
            // need to check username/password against secure credential db

            // authorize
            // Check that the user provided a valid VMM user
            if (!IsValidUserRole())
            {
                MessageBox.Show("Please create a user and try again");
                addUserTab.Visible = false;
                label2.Text = "Please sign in.";
                return;
            }

            label2.Text = "Welcome " + user.Text;
            if (user.Text == "Administrator")
            {
                AdminLoggedIn();
            }
            else
            {
                TenantLoggedIn();
            }
        }

        private void signOutButton_Click(object sender, EventArgs e)
        {
            addUserTab.Visible = false;
            label2.Text = "Please sign in.";
        }

        private void refreshVmButton_Click(object sender, EventArgs e)
        {
            var vms = GetVMs();
            BindingList<VirtualMachine> vmBindingList = null;
            vmBindingList = new BindingList<VirtualMachine>(new List<VirtualMachine>(vms));
            vmView.DataSource = vmBindingList;
            vmView.Columns.Clear();
            vmView.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName = "Id", HeaderText = "Id" });
            vmView.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName = "StampId", HeaderText = "StampId" });
            vmView.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName = "Name", HeaderText = "Name" });
            vmView.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName = "Status", HeaderText = "Status" });
        }

        private void addUser_Click(object sender, EventArgs e)
        {
            CreateUserRole(newUserTextBox.Text);
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < vmView.Rows.Count; i++ )
            {
                if (vmView.Rows[i].Selected)
                {
                    StartVm(new Guid(vmView.Rows[i].Cells[0].Value.ToString()));
                }
            }
        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < vmView.Rows.Count; i++ )
            {
                if (vmView.Rows[i].Selected)
                {
                    StopVm(new Guid(vmView.Rows[i].Cells[0].Value.ToString()));
                }
            }
        }

        private void deleteVmButton_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < vmView.Rows.Count; i++ )
            {
                if (vmView.Rows[i].Selected)
                {
                    DeleteVm(new Guid(vmView.Rows[i].Cells[0].Value.ToString()));
                }
            }
        }

        private void createVmButton_Click(object sender, EventArgs e)
        {
            CreateVm(vmNameTextBox.Text, vhdNameTextBox.Text);
        }

        private void refreshButton_Click(object sender, EventArgs e)
        {
            var userRoles = GetUserRoles();
            var userRoleBindingList = new BindingList<UserRole>(new List<UserRole>(userRoles));
            userRoleView.DataSource = userRoleBindingList;
            userRoleView.Columns.Clear();
            userRoleView.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName = "Id", HeaderText = "Id" });
            userRoleView.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName = "Name", HeaderText = "Name" });
        }

        private void deleteUser_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < userRoleView.Rows.Count; i++)
            {
                if (userRoleView.Rows[i].Selected)
                {
                    DeleteUserRole(new Guid(userRoleView.Rows[i].Cells[0].Value.ToString()));
                }
            }
        }
        #endregion
    }
}
 